Added GdkRGBA properties to GtkTextTag.
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Wed, 9 Feb 2011 14:41:39 +0000 (23:41 +0900)
committerMatthias Clasen <mclasen@redhat.com>
Fri, 6 May 2011 21:05:10 +0000 (17:05 -0400)
This now allows text view to render text with alpha values in
the text foreground and backgrounds, the work is almost complete,
currently the error-underline-color is still a GdkColor style property
and since we use only GdkRGBA for rendering it needs to be converted
and applied, probably a new rgba version of the style property should
also be introduced.

This commit adds tests/testtextview that must be run from the tests/
directory to show translucent text in action.

gtk/gtktextattributes.c
gtk/gtktextattributes.h
gtk/gtktextdisplay.c
gtk/gtktextlayout.c
gtk/gtktextlayout.h
gtk/gtktexttag.c
tests/Makefile.am
tests/testtextview.c [new file with mode: 0644]

index d2a9c6c3d52f0da4931d7a4e4dc2f40c043337ca..67c3db392a5bb322915dd26b773b3b6bfdb3fe6a 100644 (file)
  * Creates a #GtkTextAttributes, which describes
  * a set of properties on some text.
  * 
- * Return value: a new #GtkTextAttributes
- **/
+ * Return value: a new #GtkTextAttributes,
+ *     free with gtk_text_attributes_unref().
+ */
 GtkTextAttributes*
 gtk_text_attributes_new (void)
 {
   GtkTextAttributes *values;
 
-  values = g_new0 (GtkTextAttributes, 1);
+  values = g_slice_new0 (GtkTextAttributes);
 
   /* 0 is a valid value for most of the struct */
-
   values->refcount = 1;
 
   values->language = gtk_get_default_language ();
@@ -79,18 +79,19 @@ gtk_text_attributes_new (void)
   values->font_scale = 1.0;
 
   values->editable = TRUE;
-      
+
   return values;
 }
 
 /**
  * gtk_text_attributes_copy:
  * @src: a #GtkTextAttributes to be copied
- * 
+ *
  * Copies @src and returns a new #GtkTextAttributes.
- * 
- * Return value: a copy of @src
- **/
+ *
+ * Return value: a copy of @src,
+ *     free with gtk_text_attributes_unref()
+ */
 GtkTextAttributes*
 gtk_text_attributes_copy (GtkTextAttributes *src)
 {
@@ -110,10 +111,10 @@ G_DEFINE_BOXED_TYPE (GtkTextAttributes, gtk_text_attributes,
  * gtk_text_attributes_copy_values:
  * @src: a #GtkTextAttributes
  * @dest: another #GtkTextAttributes
- * 
- * Copies the values from @src to @dest so that @dest has the same values
- * as @src. Frees existing values in @dest.
- **/
+ *
+ * Copies the values from @src to @dest so that @dest has
+ * the same values as @src. Frees existing values in @dest.
+ */
 void
 gtk_text_attributes_copy_values (GtkTextAttributes *src,
                                  GtkTextAttributes *dest)
@@ -124,10 +125,24 @@ gtk_text_attributes_copy_values (GtkTextAttributes *src,
     return;
 
   /* Remove refs */
+  if (dest->tabs)
+    pango_tab_array_free (dest->tabs);
 
   if (dest->font)
     pango_font_description_free (dest->font);
-  
+
+  if (dest->pg_bg_color)
+    gdk_color_free (dest->pg_bg_color);
+
+  if (dest->pg_bg_rgba)
+    gdk_rgba_free (dest->pg_bg_rgba);
+
+  if (dest->appearance.rgba[0])
+    gdk_rgba_free (dest->appearance.rgba[0]);
+
+  if (dest->appearance.rgba[1])
+    gdk_rgba_free (dest->appearance.rgba[1]);
+
   /* Copy */
   orig_refcount = dest->refcount;
 
@@ -138,12 +153,21 @@ gtk_text_attributes_copy_values (GtkTextAttributes *src,
 
   dest->language = src->language;
 
-  if (dest->font)
+  if (src->font)
     dest->font = pango_font_description_copy (src->font);
-  
+
   if (src->pg_bg_color)
     dest->pg_bg_color = gdk_color_copy (src->pg_bg_color);
 
+  if (src->pg_bg_rgba)
+    dest->pg_bg_rgba = gdk_rgba_copy (src->pg_bg_rgba);
+
+  if (src->appearance.rgba[0])
+    dest->appearance.rgba[0] = gdk_rgba_copy (src->appearance.rgba[0]);
+
+  if (src->appearance.rgba[1])
+    dest->appearance.rgba[1] = gdk_rgba_copy (src->appearance.rgba[1]);
+
   dest->refcount = orig_refcount;
 }
 
@@ -191,7 +215,16 @@ gtk_text_attributes_unref (GtkTextAttributes *values)
       if (values->pg_bg_color)
        gdk_color_free (values->pg_bg_color);
 
-      g_free (values);
+      if (values->pg_bg_rgba)
+       gdk_rgba_free (values->pg_bg_rgba);
+
+      if (values->appearance.rgba[0])
+       gdk_rgba_free (values->appearance.rgba[0]);
+
+      if (values->appearance.rgba[1])
+       gdk_rgba_free (values->appearance.rgba[1]);
+
+      g_slice_free (GtkTextAttributes, values);
     }
 }
 
@@ -216,16 +249,41 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
 
       if (tag->priv->bg_color_set)
         {
-          dest->appearance.bg_color = vals->appearance.bg_color;
+         if (dest->appearance.rgba[0])
+           {
+             gdk_rgba_free (dest->appearance.rgba[0]);
+             dest->appearance.rgba[0] = NULL;
+           }
+
+         if (vals->appearance.rgba[0])
+           dest->appearance.rgba[0] = gdk_rgba_copy (vals->appearance.rgba[0]);
 
           dest->appearance.draw_bg = TRUE;
         }
+
       if (tag->priv->fg_color_set)
-        dest->appearance.fg_color = vals->appearance.fg_color;
+       {
+         if (dest->appearance.rgba[1])
+           {
+             gdk_rgba_free (dest->appearance.rgba[1]);
+             dest->appearance.rgba[1] = NULL;
+           }
+
+         if (vals->appearance.rgba[1])
+           dest->appearance.rgba[1] = gdk_rgba_copy (vals->appearance.rgba[1]);
+       }
 
       if (tag->priv->pg_bg_color_set)
         {
-          dest->pg_bg_color = gdk_color_copy (vals->pg_bg_color);
+         if (dest->pg_bg_rgba)
+           {
+             gdk_rgba_free (dest->pg_bg_rgba);
+             dest->pg_bg_rgba = NULL;
+
+           }
+
+         if (vals->pg_bg_rgba)
+           dest->pg_bg_rgba = gdk_rgba_copy (vals->pg_bg_rgba);
         }
 
       if (vals->font)
index aa7d6f8aa895da62c630ca206f52e485508f9ac0..12c1af70637b7b7d8d3c9af481d5fda3356b81b5 100644 (file)
@@ -102,8 +102,12 @@ struct _GtkTextAppearance
   guint inside_selection : 1;
   guint is_text : 1;
 
-  /*< private >*/
-  guint padding[4];
+  GdkRGBA *rgba[2];
+
+#if __SIZEOF_INT__ == __SIZEOF_POINTER__
+  /* unusable, just for ABI compat */
+  guint padding[2];
+#endif
 };
 
 struct _GtkTextAttributes
@@ -155,7 +159,9 @@ struct _GtkTextAttributes
   guint editable : 1;
 
   /*< private >*/
-  guint padding[4];
+  GdkRGBA *pg_bg_rgba;
+
+  guint padding[3];
 };
 
 GtkTextAttributes* gtk_text_attributes_new         (void);
index e9a24bc5f3bf47c4a3c8d434be4ac529d2fd6f17..e3ec766dcbc13138c049317a5aa1732c7ccb9e99 100644 (file)
@@ -110,8 +110,11 @@ struct _GtkTextRenderer
   
   GdkColor *error_color;       /* Error underline color for this widget */
   GList *widgets;              /* widgets encountered when drawing */
-  
-  int state;
+
+  GdkRGBA rgba[4];
+  guint8  rgba_set[4];
+
+  guint state : 2;
 };
 
 struct _GtkTextRendererClass
@@ -121,46 +124,35 @@ struct _GtkTextRendererClass
 
 G_DEFINE_TYPE (GtkTextRenderer, _gtk_text_renderer, PANGO_TYPE_RENDERER)
 
-static void
-text_renderer_set_gdk_color (GtkTextRenderer *text_renderer,
-                            PangoRenderPart  part,
-                            GdkColor        *gdk_color)
-{
-  PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
-
-  if (gdk_color)
-    {
-      PangoColor color;
-
-      color.red = gdk_color->red;
-      color.green = gdk_color->green;
-      color.blue = gdk_color->blue;
-      
-      pango_renderer_set_color (renderer, part, &color);
-    }
-  else
-    pango_renderer_set_color (renderer, part, NULL);
-}
-
 static void
 text_renderer_set_rgba (GtkTextRenderer *text_renderer,
                        PangoRenderPart  part,
-                       GdkRGBA         *rgba)
+                       const GdkRGBA   *rgba)
 {
   PangoRenderer *renderer = PANGO_RENDERER (text_renderer);
+  PangoColor     dummy = { 0, };
+
+  if ((!rgba && !text_renderer->rgba_set[part]) ||
+      (rgba && text_renderer->rgba_set[part] &&
+       text_renderer->rgba[part].red == rgba->red &&
+       text_renderer->rgba[part].green == rgba->green &&
+       text_renderer->rgba[part].blue == rgba->blue &&
+       text_renderer->rgba[part].alpha == rgba->alpha))
+    return;
 
   if (rgba)
     {
-      PangoColor color;
+      text_renderer->rgba_set[part] = TRUE;
+      text_renderer->rgba[part] = *rgba;
 
-      color.red = CLAMP (rgba->red * 65535. + 0.5, 0, 65535);
-      color.green = CLAMP (rgba->green * 65535. + 0.5, 0, 65535);
-      color.blue = CLAMP (rgba->blue * 65535. + 0.5, 0, 65535);
-
-      pango_renderer_set_color (renderer, part, &color);
+      pango_renderer_set_color (renderer, part, &dummy);
     }
   else
-    pango_renderer_set_color (renderer, part, NULL);
+    {
+      text_renderer->rgba_set[part] = FALSE;
+
+      pango_renderer_set_color (renderer, part, NULL);
+    }
 }
 
 static GtkTextAppearance *
@@ -188,9 +180,8 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
   GtkStyleContext *context;
   GtkStateFlags state;
   GtkTextRenderer *text_renderer = GTK_TEXT_RENDERER (renderer);
-  GdkColor *bg_color = NULL;
+  GdkRGBA *bg_rgba = NULL;
   GdkRGBA *fg_rgba = NULL;
-  GdkColor *fg_color = NULL;
   GtkTextAppearance *appearance;
 
   PANGO_RENDERER_CLASS (_gtk_text_renderer_parent_class)->prepare_run (renderer, run);
@@ -199,15 +190,14 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
   g_assert (appearance != NULL);
 
   context = gtk_widget_get_style_context (text_renderer->widget);
-
-  state = gtk_widget_get_state_flags (text_renderer->widget);
+  state   = gtk_widget_get_state_flags (text_renderer->widget);
 
   if (appearance->draw_bg && text_renderer->state == NORMAL)
-    bg_color = &appearance->bg_color;
+    bg_rgba = appearance->rgba[0];
   else
-    bg_color = NULL;
+    bg_rgba = NULL;
   
-  text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_color);
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_BACKGROUND, bg_rgba);
 
   if (text_renderer->state == SELECTED)
     {
@@ -224,18 +214,10 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
                               NULL);
     }
   else
-    fg_color = &appearance->fg_color;
+    fg_rgba = appearance->rgba[1];
 
-  if (fg_rgba)
-    {
-      text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba);
-      text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH,fg_rgba);
-    }
-  else
-    {
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_color);
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH, fg_color);
-    }
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_FOREGROUND, fg_rgba);
+  text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_STRIKETHROUGH,fg_rgba);
 
   if (appearance->underline == PANGO_UNDERLINE_ERROR)
     {
@@ -252,28 +234,24 @@ gtk_text_renderer_prepare_run (PangoRenderer  *renderer,
             }
         }
 
-      text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color);
+      // XXX Transform the gdk color to an gdk rgba here 
+      //text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, text_renderer->error_color);
     }
-  else if (fg_rgba)
-    text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
   else
-    text_renderer_set_gdk_color (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_color);
+    text_renderer_set_rgba (text_renderer, PANGO_RENDER_PART_UNDERLINE, fg_rgba);
+
+  if (fg_rgba != appearance->rgba[1])
+    gdk_rgba_free (fg_rgba);
 }
 
 static void
 set_color (GtkTextRenderer *text_renderer,
            PangoRenderPart  part)
 {
-  PangoColor *color;
-
   cairo_save (text_renderer->cr);
 
-  color = pango_renderer_get_color (PANGO_RENDERER (text_renderer), part);
-  if (color)
-    cairo_set_source_rgb (text_renderer->cr,
-                          color->red / 65535.,
-                          color->green / 65535.,
-                          color->blue / 65535.);
+  if (text_renderer->rgba_set[part])
+    gdk_cairo_set_source_rgba (text_renderer->cr, &text_renderer->rgba[part]);
 }
 
 static void
index 35809873d554ac8c78c10bfd98750949a539fddd..f19ab618d26509f32f4af70f6fdcf808f11b9ae1 100644 (file)
@@ -1424,9 +1424,27 @@ gtk_text_attr_appearance_destroy (PangoAttribute *attr)
 {
   GtkTextAttrAppearance *appearance_attr = (GtkTextAttrAppearance *)attr;
 
+  if (appearance_attr->appearance.rgba[0])
+    gdk_rgba_free (appearance_attr->appearance.rgba[0]);
+
+  if (appearance_attr->appearance.rgba[1])
+    gdk_rgba_free (appearance_attr->appearance.rgba[1]);
+
   g_slice_free (GtkTextAttrAppearance, appearance_attr);
 }
 
+static gboolean 
+rgba_equal (const GdkRGBA *rgba1, const GdkRGBA *rgba2)
+{
+  if (rgba1 && rgba2)
+    return gdk_rgba_equal (rgba1, rgba2);
+  
+  if (rgba1 || rgba2)
+    return FALSE;
+
+  return TRUE;
+}
+
 static gboolean
 gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
                                   const PangoAttribute *attr2)
@@ -1434,8 +1452,8 @@ gtk_text_attr_appearance_compare (const PangoAttribute *attr1,
   const GtkTextAppearance *appearance1 = &((const GtkTextAttrAppearance *)attr1)->appearance;
   const GtkTextAppearance *appearance2 = &((const GtkTextAttrAppearance *)attr2)->appearance;
 
-  return (gdk_color_equal (&appearance1->fg_color, &appearance2->fg_color) &&
-          gdk_color_equal (&appearance1->bg_color, &appearance2->bg_color) &&
+  return (rgba_equal (appearance1->rgba[0], appearance2->rgba[0]) &&
+          rgba_equal (appearance1->rgba[1], appearance2->rgba[1]) &&
           appearance1->underline == appearance2->underline &&
           appearance1->strikethrough == appearance2->strikethrough &&
           appearance1->draw_bg == appearance2->draw_bg);
@@ -1472,6 +1490,12 @@ gtk_text_attr_appearance_new (const GtkTextAppearance *appearance)
 
   result->appearance = *appearance;
 
+  if (appearance->rgba[0])
+    result->appearance.rgba[0] = gdk_rgba_copy (appearance->rgba[0]);
+
+  if (appearance->rgba[1])
+    result->appearance.rgba[1] = gdk_rgba_copy (appearance->rgba[1]);
+
   return (PangoAttribute *)result;
 }
 
index 4e9533d0eb78d0c994ca05fd40e984814cdedfba..09ca01c5b0cec330e821f8f8f4c15f614e585a18 100644 (file)
@@ -233,6 +233,7 @@ struct _GtkTextCursorDisplay
   guint is_strong : 1;
   guint is_weak : 1;
 };
+
 struct _GtkTextLineDisplay
 {
   PangoLayout *layout;
index 1a653b3b5359540a5e69dc8e99f326feb41efe1a..dbfb5aea36d5c6a39cfd37f7267d2a5551ba37a0 100644 (file)
@@ -92,6 +92,8 @@ enum {
   PROP_FOREGROUND,
   PROP_BACKGROUND_GDK,
   PROP_FOREGROUND_GDK,
+  PROP_BACKGROUND_RGBA,
+  PROP_FOREGROUND_RGBA,
   PROP_FONT,
   PROP_FONT_DESC,
   PROP_FAMILY,
@@ -121,6 +123,7 @@ enum {
   PROP_INVISIBLE,
   PROP_PARAGRAPH_BACKGROUND,
   PROP_PARAGRAPH_BACKGROUND_GDK,
+  PROP_PARAGRAPH_BACKGROUND_RGBA,
 
   /* Behavior args */
   PROP_ACCUMULATIVE_MARGIN,
@@ -206,6 +209,15 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GDK_TYPE_COLOR,
                                                        GTK_PARAM_READWRITE));
 
+
+  g_object_class_install_property (object_class,
+                                   PROP_BACKGROUND_RGBA,
+                                   g_param_spec_boxed ("background-rgba",
+                                                       P_("Background rgba"),
+                                                       P_("Background rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
   g_object_class_install_property (object_class,
                                    PROP_BACKGROUND_FULL_HEIGHT,
                                    g_param_spec_boolean ("background-full-height",
@@ -230,6 +242,14 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GDK_TYPE_COLOR,
                                                        GTK_PARAM_READWRITE));
 
+  g_object_class_install_property (object_class,
+                                   PROP_FOREGROUND_RGBA,
+                                   g_param_spec_boxed ("foreground-rgba",
+                                                       P_("Foreground rgba"),
+                                                       P_("Foreground rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
   g_object_class_install_property (object_class,
                                    PROP_DIRECTION,
                                    g_param_spec_enum ("direction",
@@ -531,6 +551,22 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
                                                        GDK_TYPE_COLOR,
                                                        GTK_PARAM_READWRITE));
 
+  /**
+   * GtkTextTag:paragraph-background-rgba:
+   *
+   * The paragraph background color as a as a (possibly unallocated) 
+   * #GdkRGBA.
+   *
+   * Since: 3.2
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_PARAGRAPH_BACKGROUND_RGBA,
+                                   g_param_spec_boxed ("paragraph-background-rgba",
+                                                       P_("Paragraph background rgba"),
+                                                       P_("Paragraph background rgba as a (possibly unallocated) GdkRGBA"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
+
   /**
    * GtkTextTag:accumulative-margin:
    *
@@ -740,11 +776,16 @@ gtk_text_tag_finalize (GObject *object)
 }
 
 static void
-set_bg_color (GtkTextTag *tag, GdkColor *color)
+set_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->appearance.rgba[0])
+    gdk_rgba_free (priv->values->appearance.rgba[0]);
+
+  priv->values->appearance.rgba[0] = NULL;
+
+  if (rgba)
     {
       if (!priv->bg_color_set)
         {
@@ -752,7 +793,7 @@ set_bg_color (GtkTextTag *tag, GdkColor *color)
           g_object_notify (G_OBJECT (tag), "background-set");
         }
 
-      priv->values->appearance.bg_color = *color;
+      priv->values->appearance.rgba[0] = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -765,18 +806,24 @@ set_bg_color (GtkTextTag *tag, GdkColor *color)
 }
 
 static void
-set_fg_color (GtkTextTag *tag, GdkColor *color)
+set_fg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->appearance.rgba[1])
+    gdk_rgba_free (priv->values->appearance.rgba[1]);
+
+  priv->values->appearance.rgba[1] = NULL;
+
+  if (rgba)
     {
       if (!priv->fg_color_set)
         {
           priv->fg_color_set = TRUE;
           g_object_notify (G_OBJECT (tag), "foreground-set");
         }
-      priv->values->appearance.fg_color = *color;
+
+      priv->values->appearance.rgba[1] = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -789,21 +836,24 @@ set_fg_color (GtkTextTag *tag, GdkColor *color)
 }
 
 static void
-set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
+set_pg_bg_rgba (GtkTextTag *tag, GdkRGBA *rgba)
 {
   GtkTextTagPrivate *priv = tag->priv;
 
-  if (color)
+  if (priv->values->pg_bg_rgba)
+    gdk_rgba_free (priv->values->pg_bg_rgba);
+
+  priv->values->pg_bg_rgba = NULL;
+
+  if (rgba)
     {
       if (!priv->pg_bg_color_set)
         {
           priv->pg_bg_color_set = TRUE;
           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
         }
-      else
-       gdk_color_free (priv->values->pg_bg_color);
 
-      priv->values->pg_bg_color = gdk_color_copy (color);
+      priv->values->pg_bg_rgba = gdk_rgba_copy (rgba);
     }
   else
     {
@@ -811,11 +861,63 @@ set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
         {
           priv->pg_bg_color_set = FALSE;
           g_object_notify (G_OBJECT (tag), "paragraph-background-set");
-         gdk_color_free (priv->values->pg_bg_color);
         }
+    }
+}
 
-      priv->values->pg_bg_color = NULL;
+
+static void
+set_bg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_bg_rgba (tag, &rgba);
     }
+  else
+    set_bg_rgba (tag, NULL);
+}
+
+static void
+set_fg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_fg_rgba (tag, &rgba);
+    }
+  else
+    set_fg_rgba (tag, NULL);
+}
+
+static void
+set_pg_bg_color (GtkTextTag *tag, GdkColor *color)
+{
+  if (color)
+    {
+      gchar  *str;
+      GdkRGBA rgba;
+
+      str = gdk_color_to_string (color);
+      gdk_rgba_parse (&rgba, str);
+      g_free (str);
+
+      set_pg_bg_rgba (tag, &rgba);
+    }
+  else
+    set_pg_bg_rgba (tag, NULL);
 }
 
 static PangoFontMask
@@ -998,12 +1100,12 @@ gtk_text_tag_set_property (GObject      *object,
 
     case PROP_BACKGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_bg_color (text_tag, NULL);       /* reset to background_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_bg_color (text_tag, &color);
+          set_bg_rgba (text_tag, NULL);       /* reset background_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_bg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1013,12 +1115,12 @@ gtk_text_tag_set_property (GObject      *object,
 
     case PROP_FOREGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_fg_color (text_tag, NULL);       /* reset to foreground_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_fg_color (text_tag, &color);
+          set_fg_rgba (text_tag, NULL);       /* reset to foreground_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_fg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1042,6 +1144,22 @@ gtk_text_tag_set_property (GObject      *object,
       }
       break;
 
+    case PROP_BACKGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_bg_rgba (text_tag, color);
+      }
+      break;
+
+    case PROP_FOREGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_fg_rgba (text_tag, color);
+      }
+      break;
+
     case PROP_FONT:
       {
         PangoFontDescription *font_desc = NULL;
@@ -1255,12 +1373,12 @@ gtk_text_tag_set_property (GObject      *object,
       
     case PROP_PARAGRAPH_BACKGROUND:
       {
-        GdkColor color;
+        GdkRGBA rgba;
 
         if (!g_value_get_string (value))
-          set_pg_bg_color (text_tag, NULL);       /* reset to paragraph_background_set to FALSE */
-        else if (gdk_color_parse (g_value_get_string (value), &color))
-          set_pg_bg_color (text_tag, &color);
+          set_pg_bg_rgba (text_tag, NULL);       /* reset paragraph_background_set to FALSE */
+        else if (gdk_rgba_parse (&rgba, g_value_get_string (value)))
+          set_pg_bg_rgba (text_tag, &rgba);
         else
           g_warning ("Don't know color `%s'", g_value_get_string (value));
 
@@ -1276,6 +1394,14 @@ gtk_text_tag_set_property (GObject      *object,
       }
       break;
 
+    case PROP_PARAGRAPH_BACKGROUND_RGBA:
+      {
+        GdkRGBA *color = g_value_get_boxed (value);
+
+        set_pg_bg_rgba (text_tag, color);
+      }
+      break;
+
     case PROP_ACCUMULATIVE_MARGIN:
       priv->accumulative_margin = g_value_get_boolean (value);
       g_object_notify (object, "accumulative-margin");
@@ -1429,6 +1555,7 @@ gtk_text_tag_get_property (GObject      *object,
 {
   GtkTextTag *tag = GTK_TEXT_TAG (object);
   GtkTextTagPrivate *priv = tag->priv;
+  GdkColor color = { 0, };
 
   switch (prop_id)
     {
@@ -1437,10 +1564,22 @@ gtk_text_tag_get_property (GObject      *object,
       break;
 
     case PROP_BACKGROUND_GDK:
-      g_value_set_boxed (value, &priv->values->appearance.bg_color);
+      if (priv->values->appearance.rgba[0])
+       {
+         color.red   = CLAMP (priv->values->appearance.rgba[0]->red,   0.0, 1.0) * 65535.0;
+         color.green = CLAMP (priv->values->appearance.rgba[0]->green, 0.0, 1.0) * 65535.0;
+         color.blue  = CLAMP (priv->values->appearance.rgba[0]->blue,  0.0, 1.0) * 65535.0;
+       }
+      g_value_set_boxed (value, &color);
       break;
 
     case PROP_FOREGROUND_GDK:
+      if (priv->values->appearance.rgba[1])
+       {
+         color.red   = CLAMP (priv->values->appearance.rgba[1]->red,   0.0, 1.0) * 65535.0;
+         color.green = CLAMP (priv->values->appearance.rgba[1]->green, 0.0, 1.0) * 65535.0;
+         color.blue  = CLAMP (priv->values->appearance.rgba[1]->blue,  0.0, 1.0) * 65535.0;
+       }
       g_value_set_boxed (value, &priv->values->appearance.fg_color);
       break;
 
@@ -1574,6 +1713,7 @@ gtk_text_tag_get_property (GObject      *object,
       break;
       
     case PROP_PARAGRAPH_BACKGROUND_GDK:
+      /* XXX Transform the GdkRGBA here */
       g_value_set_boxed (value, priv->values->pg_bg_color);
       break;
 
index f4029a9884204758e39d11862736aa1fa697782f..3ea7981cc070d723de9bd75f43ee152640ccb06d 100644 (file)
@@ -108,7 +108,8 @@ noinst_PROGRAMS =  $(TEST_PROGS)    \
        testtoplevelembed               \
        testnoscreen                    \
        testtreepos                     \
-       testsensitive
+       testsensitive                   \
+       testtextview
 
 if USE_X11
 noinst_PROGRAMS += testerrors
@@ -207,6 +208,7 @@ testtoplevelembed_DEPENDENCIES = $(TEST_DEPS)
 testnoscreen_DEPENDENCIES = $(TEST_DEPS)
 testtreepos_DEPENDENCIES = $(TEST_DEPS)
 testsensitive_DEPENDENCIES = $(TEST_DEPS)
+testtextview_DEPENDENCIES = $(TEST_DEPS)
 
 flicker_LDADD = $(LDADDS)
 simple_LDADD = $(LDADDS)
@@ -291,6 +293,7 @@ testtoplevelembed_LDADD = $(LDADDS)
 testnoscreen_LDADD = $(LDADDS)
 testtreepos_LDADD = $(LDADDS)
 testsensitive_LDADD = $(LDADDS)
+testtextview_LDADD = $(LDADDS)
 
 
 testentrycompletion_SOURCES =  \
@@ -436,6 +439,9 @@ styleexamples_SOURCES = styleexamples.c
 
 testtoplevelembed_SOURCES = testtoplevelembed.c
 
+testtextview_SOURCES = testtextview.c
+
+
 EXTRA_DIST +=                  \
        gradient1.png           \
        prop-editor.h           \
diff --git a/tests/testtextview.c b/tests/testtextview.c
new file mode 100644 (file)
index 0000000..2a7701f
--- /dev/null
@@ -0,0 +1,151 @@
+
+
+#include "config.h"
+#include <gtk/gtk.h>
+
+
+static void
+create_tags (GtkTextBuffer *buffer)
+{
+
+  gtk_text_buffer_create_tag (buffer, "italic",
+                              "style", PANGO_STYLE_ITALIC, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "bold",
+                              "weight", PANGO_WEIGHT_BOLD, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "x-large",
+                              "scale", PANGO_SCALE_X_LARGE, NULL);
+
+  gtk_text_buffer_create_tag (buffer, "semi_blue_foreground",
+                              "foreground", "rgba(0,0,255,0.5)", NULL);
+
+  gtk_text_buffer_create_tag (buffer, "semi_red_background",
+                              "background", "rgba(255,0,0,0.5)", NULL);
+
+  gtk_text_buffer_create_tag (buffer, "word_wrap",
+                              "wrap_mode", GTK_WRAP_WORD, NULL);
+}
+
+
+static void
+insert_text (GtkTextBuffer *buffer)
+{
+  GtkTextIter iter;
+  GtkTextIter start, end;
+
+  /* get start of buffer; each insertion will revalidate the
+   * iterator to point to just after the inserted text.
+   */
+  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+
+  gtk_text_buffer_insert (buffer, &iter,
+      "This test shows text view rendering some text with rgba colors.\n\n", -1);
+
+  gtk_text_buffer_insert (buffer, &iter, "For example, you can have ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "italic translucent blue text", -1,
+                                            "italic", 
+                                           "semi_blue_foreground",
+                                           "x-large",
+                                           NULL);
+
+  gtk_text_buffer_insert (buffer, &iter, ", or ", -1);
+
+  gtk_text_buffer_insert (buffer, &iter, ", ", -1);
+  gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
+                                            "bold text with translucent red background", -1,
+                                            "bold", 
+                                           "semi_red_background",
+                                           "x-large",
+                                           NULL);
+  gtk_text_buffer_insert (buffer, &iter, ".", -1);
+
+  /* Apply word_wrap tag to whole buffer */
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+  gtk_text_buffer_apply_tag_by_name (buffer, "word_wrap", &start, &end);
+}
+
+
+static cairo_pattern_t *
+get_pattern (void)
+{
+  static cairo_pattern_t *static_pattern = NULL;
+
+  if (!static_pattern)
+    {
+      cairo_surface_t *surface = 
+       cairo_image_surface_create_from_png ("gradient1.png");
+
+      if (surface)
+       {
+         static_pattern = cairo_pattern_create_for_surface (surface);
+         cairo_pattern_set_extend (static_pattern, CAIRO_EXTEND_REFLECT);
+       }
+      else 
+       g_warning ("Failed to create surface for gradient1.png\n");
+    }
+  return static_pattern;
+}
+
+static void
+draw_background (GtkWidget *widget, cairo_t *cr)
+{
+  GtkAllocation allocation;
+  cairo_pattern_t *pat;
+  
+  gtk_widget_get_allocation (widget, &allocation);
+
+  cairo_save (cr);
+
+#if 0
+  pat = cairo_pattern_create_linear (0.0, 0.0,  30.0, 30.0);
+  cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 0, 1);
+  cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, 1);
+  cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
+  cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+  cairo_set_source (cr, pat);
+  cairo_fill (cr);
+  cairo_pattern_destroy (pat);
+
+#else
+
+  if (get_pattern ())
+    {
+      cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
+      cairo_set_source (cr, get_pattern ());
+      cairo_fill (cr);
+    }
+#endif
+
+  cairo_restore (cr);
+}
+
+int
+main (int argc, char **argv)
+{
+  GtkWidget *window, *textview;
+  GtkTextBuffer *buffer;
+
+  gtk_init (&argc, &argv);
+
+  window   = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  textview = gtk_text_view_new ();
+  buffer   = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
+
+  create_tags (buffer);
+  insert_text (buffer);
+  
+  gtk_widget_show (textview);
+  gtk_container_add (GTK_CONTAINER (window), textview);
+
+  g_signal_connect (textview, "draw",
+                   G_CALLBACK (draw_background), NULL);
+
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}